/*
www.sourceforge.net/projects/tinyxml
Original code	(2.0 and earlier )copyright	(c)	2000-2002	Lee	Thomason (www.grinninglizard.com)

This software	is provided	'as-is', without any express or	implied
warranty.	In no	event	will the authors be	held liable	for	any
damages	arising	from the use of	this software.

Permission is	granted	to anyone	to use this	software for any
purpose, including commercial	applications,	and	to alter it	and
redistribute it	freely,	subject	to the following restrictions:

1. The origin	of this	software must	not	be misrepresented; you must
not	claim	that you wrote the original	software.	If you use this
software in	a	product, an	acknowledgment in	the	product	documentation
would	be appreciated but is	not	required.

2. Altered source	versions must	be plainly marked	as such, and
must not be	misrepresented as	being	the	original software.

3. This	notice may not be	removed	or altered from	any	source
distribution.
 */

#include <ctype.h>
#ifdef _MSC_VER
#pragma warning(disable:4996) // Disabling stupid .NET deprecated warning.
#endif

#include "NXU_tinyxml.h"
#include "NXU_File.h"

#ifdef TIXML_USE_STL
#include <sstream>
#include <iostream>
#endif

namespace	NXU
{


bool TiXmlBase::condenseWhiteSpace = true;

void TiXmlBase::PutString(const	TIXML_STRING &str, TIXML_OSTREAM *stream)
{
	TIXML_STRING buffer;
	PutString(str, &buffer);
	(*stream)	<< buffer;
}

void TiXmlBase::PutString(const	TIXML_STRING &str, TIXML_STRING	*outString)
{
	int	i	=	0;

	while	(i < (int)str.length())
	{
		unsigned char	c	=	(unsigned	char)str[i];

		if (c	== '&' &&	i	<	((int)str.length() - 2)	&& str[i + 1]	== '#' &&	str[i	+	2] ==	'x')
		{
			// Hexadecimal character reference.
			// Pass	through	unchanged.
			// &#xA9;	 --	copyright	symbol,	for	example.
			//
			// The -1	is a bug fix from	Rob	Laveaux. It	keeps
			// an	overflow from	happening	if there is	no ';'.
			// There are actually	2	ways to	exit this	loop -
			// while fails (error	case)	and	break	(semicolon found).
			// However,	there	is no	mechanism	(currently)	for
			// this	function to	return an	error.
			while	(i < (int)str.length() - 1)
			{
				outString->append(str.c_str()	+	i, 1);
				++i;
				if (str[i] ==	';')
				{
					break;
				}
			}
		}
		else if	(c ==	'&')
		{
			outString->append(entity[0].str, entity[0].strLength);
			++i;
		}
		else if	(c ==	'<')
		{
			outString->append(entity[1].str, entity[1].strLength);
			++i;
		}
		else if	(c ==	'>')
		{
			outString->append(entity[2].str, entity[2].strLength);
			++i;
		}
		else if	(c ==	'\"')
		{
			outString->append(entity[3].str, entity[3].strLength);
			++i;
		}
		else if	(c ==	'\'')
		{
			outString->append(entity[4].str, entity[4].strLength);
			++i;
		}
		else if	(c < 32)
		{
			// Easy	pass at	non-alpha/numeric/symbol
			// Below 32	is symbolic.
			char buf[32];

			#if	defined(TIXML_SNPRINTF)
			TIXML_SNPRINTF(buf,	sizeof(buf), "&#x%02X;", (unsigned)(c	&0xff));
			#else
			sprintf(buf, "&#x%02X;", (unsigned)(c	&0xff));
			#endif

			//*ME:	warning	C4267: convert 'size_t'	to 'int'
			//*ME:	Int-Cast to	make compiler	happy	...
			outString->append(buf, (int)strlen(buf));
			++i;
		}
		else
		{
			//char realc = (char)	c;
			//outString->append( &realc, 1 );
			*outString +=	(char)c; //	somewhat more	efficient	function call.
			++i;
		}
	}
}


// <-- Strange class for a bug fix.	Search for STL_STRING_BUG
TiXmlBase::StringToBuffer::StringToBuffer(const	TIXML_STRING &str)
{
	buffer = new char[str.length() + 1];
	if (buffer)
	{
		strcpy(buffer, str.c_str());
	}
}


TiXmlBase::StringToBuffer::~StringToBuffer()
{
	delete []	buffer;
}
// End strange bug fix.	-->


TiXmlNode::TiXmlNode(NodeType	_type):	TiXmlBase()
{
	parent = 0;
	type = _type;
	firstChild = 0;
	lastChild	=	0;
	prev = 0;
	next = 0;
}


TiXmlNode::~TiXmlNode()
{
	TiXmlNode	*node	=	firstChild;
	TiXmlNode	*temp	=	0;

	while	(node)
	{
		temp = node;
		node = node->next;
		delete temp;
	}
}


void TiXmlNode::CopyTo(TiXmlNode *target)const
{
	target->SetValue(value.c_str());
	target->userData = userData;
}


void TiXmlNode::Clear()
{
	TiXmlNode	*node	=	firstChild;
	TiXmlNode	*temp	=	0;

	while	(node)
	{
		temp = node;
		node = node->next;
		delete temp;
	}

	firstChild = 0;
	lastChild	=	0;
}


TiXmlNode	*TiXmlNode::LinkEndChild(TiXmlNode *node)
{
	assert(node->parent	== 0 ||	node->parent ==	this);
	assert(node->GetDocument() ==	0	|| node->GetDocument() ==	this->GetDocument());

	node->parent = this;

	node->prev = lastChild;
	node->next = 0;

	if (lastChild)
	{
		lastChild->next	=	node;
	}
	else
	{
		firstChild = node;
	}
	// it	was	an empty list.

	lastChild	=	node;
	return node;
}


TiXmlNode	*TiXmlNode::InsertEndChild(const TiXmlNode &addThis)
{
	TiXmlNode	*node	=	addThis.Clone();
	if (!node)
	{
		return 0;
	}

	return LinkEndChild(node);
}


TiXmlNode	*TiXmlNode::InsertBeforeChild(TiXmlNode	*beforeThis, const TiXmlNode &addThis)
{
	if (!beforeThis	|| beforeThis->parent	!= this)
	{
		return 0;
	}

	TiXmlNode	*node	=	addThis.Clone();
	if (!node)
	{
		return 0;
	}
	node->parent = this;

	node->next = beforeThis;
	node->prev = beforeThis->prev;
	if (beforeThis->prev)
	{
		beforeThis->prev->next = node;
	}
	else
	{
		assert(firstChild	== beforeThis);
		firstChild = node;
	}
	beforeThis->prev = node;
	return node;
}


TiXmlNode	*TiXmlNode::InsertAfterChild(TiXmlNode *afterThis, const TiXmlNode &addThis)
{
	if (!afterThis ||	afterThis->parent	!= this)
	{
		return 0;
	}

	TiXmlNode	*node	=	addThis.Clone();
	if (!node)
	{
		return 0;
	}
	node->parent = this;

	node->prev = afterThis;
	node->next = afterThis->next;
	if (afterThis->next)
	{
		afterThis->next->prev	=	node;
	}
	else
	{
		assert(lastChild ==	afterThis);
		lastChild	=	node;
	}
	afterThis->next	=	node;
	return node;
}


TiXmlNode	*TiXmlNode::ReplaceChild(TiXmlNode *replaceThis, const TiXmlNode &withThis)
{
	if (replaceThis->parent	!= this)
	{
		return 0;
	}

	TiXmlNode	*node	=	withThis.Clone();
	if (!node)
	{
		return 0;
	}

	node->next = replaceThis->next;
	node->prev = replaceThis->prev;

	if (replaceThis->next)
	{
		replaceThis->next->prev	=	node;
	}
	else
	{
		lastChild	=	node;
	}

	if (replaceThis->prev)
	{
		replaceThis->prev->next	=	node;
	}
	else
	{
		firstChild = node;
	}

	delete replaceThis;
	node->parent = this;
	return node;
}


bool TiXmlNode::RemoveChild(TiXmlNode	*removeThis)
{
	if (removeThis->parent !=	this)
	{
		assert(0);
		return false;
	}

	if (removeThis->next)
	{
		removeThis->next->prev = removeThis->prev;
	}
	else
	{
		lastChild	=	removeThis->prev;
	}

	if (removeThis->prev)
	{
		removeThis->prev->next = removeThis->next;
	}
	else
	{
		firstChild = removeThis->next;
	}

	delete removeThis;
	return true;
}

const	TiXmlNode	*TiXmlNode::FirstChild(const char	*_value)const
{
	const	TiXmlNode	*node;
	for	(node	=	firstChild;	node;	node = node->next)
	{
		if (strcmp(node->Value(),	_value)	== 0)
		{
			return node;
		}
	}
	return 0;
}


TiXmlNode	*TiXmlNode::FirstChild(const char	*_value)
{
	TiXmlNode	*node;
	for	(node	=	firstChild;	node;	node = node->next)
	{
		if (strcmp(node->Value(),	_value)	== 0)
		{
			return node;
		}
	}
	return 0;
}


const	TiXmlNode	*TiXmlNode::LastChild(const	char *_value)const
{
	const	TiXmlNode	*node;
	for	(node	=	lastChild; node; node	=	node->prev)
	{
		if (strcmp(node->Value(),	_value)	== 0)
		{
			return node;
		}
	}
	return 0;
}

TiXmlNode	*TiXmlNode::LastChild(const	char *_value)
{
	TiXmlNode	*node;
	for	(node	=	lastChild; node; node	=	node->prev)
	{
		if (strcmp(node->Value(),	_value)	== 0)
		{
			return node;
		}
	}
	return 0;
}

const	TiXmlNode	*TiXmlNode::IterateChildren(const	TiXmlNode	*previous)const
{
	if (!previous)
	{
		return FirstChild();
	}
	else
	{
		assert(previous->parent	== this);
		return previous->NextSibling();
	}
}

TiXmlNode	*TiXmlNode::IterateChildren(TiXmlNode	*previous)
{
	if (!previous)
	{
		return FirstChild();
	}
	else
	{
		assert(previous->parent	== this);
		return previous->NextSibling();
	}
}

const	TiXmlNode	*TiXmlNode::IterateChildren(const	char *val, const TiXmlNode *previous)const
{
	if (!previous)
	{
		return FirstChild(val);
	}
	else
	{
		assert(previous->parent	== this);
		return previous->NextSibling(val);
	}
}

TiXmlNode	*TiXmlNode::IterateChildren(const	char *val, TiXmlNode *previous)
{
	if (!previous)
	{
		return FirstChild(val);
	}
	else
	{
		assert(previous->parent	== this);
		return previous->NextSibling(val);
	}
}

const	TiXmlNode	*TiXmlNode::NextSibling(const	char *_value)const
{
	const	TiXmlNode	*node;
	for	(node	=	next;	node;	node = node->next)
	{
		if (strcmp(node->Value(),	_value)	== 0)
		{
			return node;
		}
	}
	return 0;
}

TiXmlNode	*TiXmlNode::NextSibling(const	char *_value)
{
	TiXmlNode	*node;
	for	(node	=	next;	node;	node = node->next)
	{
		if (strcmp(node->Value(),	_value)	== 0)
		{
			return node;
		}
	}
	return 0;
}

const	TiXmlNode	*TiXmlNode::PreviousSibling(const	char *_value)const
{
	const	TiXmlNode	*node;
	for	(node	=	prev;	node;	node = node->prev)
	{
		if (strcmp(node->Value(),	_value)	== 0)
		{
			return node;
		}
	}
	return 0;
}

TiXmlNode	*TiXmlNode::PreviousSibling(const	char *_value)
{
	TiXmlNode	*node;
	for	(node	=	prev;	node;	node = node->prev)
	{
		if (strcmp(node->Value(),	_value)	== 0)
		{
			return node;
		}
	}
	return 0;
}

void TiXmlElement::RemoveAttribute(const char	*name)
{
	TIXML_STRING str(name);
	TiXmlAttribute *node = attributeSet.Find(str);
	if (node)
	{
		attributeSet.Remove(node);
		delete node;
	}
}

const	TiXmlElement *TiXmlNode::FirstChildElement()const
{
	const	TiXmlNode	*node;

	for	(node	=	FirstChild();	node;	node = node->NextSibling())
	{
		if (node->ToElement())
		{
			return node->ToElement();
		}
	}
	return 0;
}

TiXmlElement *TiXmlNode::FirstChildElement()
{
	TiXmlNode	*node;

	for	(node	=	FirstChild();	node;	node = node->NextSibling())
	{
		if (node->ToElement())
		{
			return node->ToElement();
		}
	}
	return 0;
}

const	TiXmlElement *TiXmlNode::FirstChildElement(const char	*_value)const
{
	const	TiXmlNode	*node;

	for	(node	=	FirstChild(_value);	node;	node = node->NextSibling(_value))
	{
		if (node->ToElement())
		{
			return node->ToElement();
		}
	}
	return 0;
}

TiXmlElement *TiXmlNode::FirstChildElement(const char	*_value)
{
	TiXmlNode	*node;

	for	(node	=	FirstChild(_value);	node;	node = node->NextSibling(_value))
	{
		if (node->ToElement())
		{
			return node->ToElement();
		}
	}
	return 0;
}

const	TiXmlElement *TiXmlNode::NextSiblingElement()const
{
	const	TiXmlNode	*node;

	for	(node	=	NextSibling(); node; node	=	node->NextSibling())
	{
		if (node->ToElement())
		{
			return node->ToElement();
		}
	}
	return 0;
}

TiXmlElement *TiXmlNode::NextSiblingElement()
{
	TiXmlNode	*node;

	for	(node	=	NextSibling(); node; node	=	node->NextSibling())
	{
		if (node->ToElement())
		{
			return node->ToElement();
		}
	}
	return 0;
}

const	TiXmlElement *TiXmlNode::NextSiblingElement(const	char *_value)const
{
	const	TiXmlNode	*node;

	for	(node	=	NextSibling(_value); node; node	=	node->NextSibling(_value))
	{
		if (node->ToElement())
		{
			return node->ToElement();
		}
	}
	return 0;
}

TiXmlElement *TiXmlNode::NextSiblingElement(const	char *_value)
{
	TiXmlNode	*node;

	for	(node	=	NextSibling(_value); node; node	=	node->NextSibling(_value))
	{
		if (node->ToElement())
		{
			return node->ToElement();
		}
	}
	return 0;
}


const	TiXmlDocument	*TiXmlNode::GetDocument()const
{
	const	TiXmlNode	*node;

	for	(node	=	this;	node;	node = node->parent)
	{
		if (node->ToDocument())
		{
			return node->ToDocument();
		}
	}
	return 0;
}

TiXmlDocument	*TiXmlNode::GetDocument()
{
	TiXmlNode	*node;

	for	(node	=	this;	node;	node = node->parent)
	{
		if (node->ToDocument())
		{
			return node->ToDocument();
		}
	}
	return 0;
}

TiXmlElement::TiXmlElement(const char	*_value):	TiXmlNode(TiXmlNode::ELEMENT)
{
	firstChild = lastChild = 0;
	value	=	_value;
}


#ifdef TIXML_USE_STL
TiXmlElement::TiXmlElement(const std::string &_value): TiXmlNode(TiXmlNode::ELEMENT)
{
	firstChild = lastChild = 0;
	value	=	_value;
}
#endif


TiXmlElement::TiXmlElement(const TiXmlElement	&copy):	TiXmlNode(TiXmlNode::ELEMENT)
{
	firstChild = lastChild = 0;
	copy.CopyTo(this);
}


void TiXmlElement::operator	=	(const TiXmlElement	&base)
{
	ClearThis();
	base.CopyTo(this);
}


TiXmlElement::~TiXmlElement()
{
	ClearThis();
}


void TiXmlElement::ClearThis()
{
	Clear();
	while	(attributeSet.First())
	{
		TiXmlAttribute *node = attributeSet.First();
		attributeSet.Remove(node);
		delete node;
	}
}


const	char *TiXmlElement::Attribute(const	char *name)const
{
	TIXML_STRING str(name);
	const	TiXmlAttribute *node = attributeSet.Find(str);

	if (node)
	{
		return node->Value();
	}

	return 0;
}


const	char *TiXmlElement::Attribute(const	char *name,	int	*i)const
{
	const	char *s	=	Attribute(name);
	if (i)
	{
		if (s)
		{
			*i = atoi(s);
		}
		else
		{
			*i = 0;
		}
	}
	return s;
}


const	char *TiXmlElement::Attribute(const	char *name,	double *d)const
{
	const	char *s	=	Attribute(name);
	if (d)
	{
		if (s)
		{
			*d = atof(s);
		}
		else
		{
			*d = 0;
		}
	}
	return s;
}


int	TiXmlElement::QueryIntAttribute(const	char *name,	int	*ival)const
{
	TIXML_STRING str(name);
	const	TiXmlAttribute *node = attributeSet.Find(str);
	if (!node)
	{
		return TIXML_NO_ATTRIBUTE;
	}

	return node->QueryIntValue(ival);
}


int	TiXmlElement::QueryDoubleAttribute(const char	*name, double	*dval)const
{
	TIXML_STRING str(name);
	const	TiXmlAttribute *node = attributeSet.Find(str);
	if (!node)
	{
		return TIXML_NO_ATTRIBUTE;
	}

	return node->QueryDoubleValue(dval);
}


void TiXmlElement::SetAttribute(const	char *name,	int	val)
{
	char buf[64];
	#if	defined(TIXML_SNPRINTF)
	TIXML_SNPRINTF(buf,	sizeof(buf), "%d", val);
	#else
	sprintf(buf, "%d", val);
	#endif
	SetAttribute(name, buf);
}


#ifdef TIXML_USE_STL
void TiXmlElement::SetAttribute(const	std::string	&name, int val)
{
	std::ostringstream oss;
	oss	<< val;
	SetAttribute(name, oss.str());
}
#endif


void TiXmlElement::SetDoubleAttribute(const	char *name,	double val)
{
	char buf[256];
	#if	defined(TIXML_SNPRINTF)
	TIXML_SNPRINTF(buf,	sizeof(buf), "%f", val);
	#else
	sprintf(buf, "%f", val);
	#endif
	SetAttribute(name, buf);
}


void TiXmlElement::SetAttribute(const	char *cname, const char	*cvalue)
{
	TIXML_STRING _name(cname);
	TIXML_STRING _value(cvalue);

	TiXmlAttribute *node = attributeSet.Find(_name);
	if (node)
	{
		node->SetValue(cvalue);
		return ;
	}

	TiXmlAttribute *attrib = new TiXmlAttribute(cname, cvalue);
	if (attrib)
	{
		attributeSet.Add(attrib);
	}
	else
	{
		TiXmlDocument	*document	=	GetDocument();
		if (document)
		{
			document->SetError(TIXML_ERROR_OUT_OF_MEMORY,	0, 0,	TIXML_ENCODING_UNKNOWN);
		}
	}
}


#ifdef TIXML_USE_STL
void TiXmlElement::SetAttribute(const	std::string	&name, const std::string &_value)
{
	TiXmlAttribute *node = attributeSet.Find(name);
	if (node)
	{
		node->SetValue(_value);
		return ;
	}

	TiXmlAttribute *attrib = new TiXmlAttribute(name,	_value);
	if (attrib)
	{
		attributeSet.Add(attrib);
	}
	else
	{
		TiXmlDocument	*document	=	GetDocument();
		if (document)
		{
			document->SetError(TIXML_ERROR_OUT_OF_MEMORY,	0, 0,	TIXML_ENCODING_UNKNOWN);
		}
	}
}
#endif


void TiXmlElement::Print(NXU_FILE	*cfile,	int	depth)const
{
	int	i;
	for	(i = 0;	i	<	depth; i++)
	{
		nxu_fprintf(cfile, "		");
	}

	nxu_fprintf(cfile, "<%s",	value.c_str());

	const	TiXmlAttribute *attrib;
	for	(attrib	=	attributeSet.First();	attrib;	attrib = attrib->Next())
	{
		nxu_fprintf(cfile, " ");
		attrib->Print(cfile, depth);
	}

	// There are 3 different formatting	approaches:
	// 1)	An element without children	is printed as	a	<foo />	node
	// 2)	An element with	only a text	child	is printed as	<foo>	text </foo>
	// 3)	An element with	children is	printed	on multiple	lines.
	TiXmlNode	*node;
	if (!firstChild)
	{
		nxu_fprintf(cfile, " />");
	}
	else if	(firstChild	== lastChild &&	firstChild->ToText())
	{
		nxu_fprintf(cfile, ">");
		firstChild->Print(cfile, depth + 1);
		nxu_fprintf(cfile, "</%s>",	value.c_str());
	}
	else
	{
		nxu_fprintf(cfile, ">");

		for	(node	=	firstChild;	node;	node = node->NextSibling())
		{
			if (!node->ToText())
			{
				nxu_fprintf(cfile, "\n");
			}
			node->Print(cfile, depth + 1);
		}
		nxu_fprintf(cfile, "\n");
		for	(i = 0;	i	<	depth; ++i)
		{
			nxu_fprintf(cfile, "		");
		}
		nxu_fprintf(cfile, "</%s>",	value.c_str());
	}
}

void TiXmlElement::StreamOut(TIXML_OSTREAM *stream)const
{
	(*stream)	<< "<" <<	value;

	const	TiXmlAttribute *attrib;
	for	(attrib	=	attributeSet.First();	attrib;	attrib = attrib->Next())
	{
		(*stream)	<< " ";
		attrib->StreamOut(stream);
	}

	// If	this node	has	children,	give it	a	closing	tag. Else
	// make	it an	empty	tag.
	TiXmlNode	*node;
	if (firstChild)
	{
		(*stream)	<< ">";

		for	(node	=	firstChild;	node;	node = node->NextSibling())
		{
			node->StreamOut(stream);
		}
		(*stream)	<< "</"	<< value <<	">";
	}
	else
	{
		(*stream)	<< " />";
	}
}


void TiXmlElement::CopyTo(TiXmlElement *target)const
{
	// superclass:
	TiXmlNode::CopyTo(target);

	// Element class:
	// Clone the attributes, then	clone	the	children.
	const	TiXmlAttribute *attribute	=	0;
	for	(attribute = attributeSet.First(); attribute;	attribute	=	attribute->Next())
	{
		target->SetAttribute(attribute->Name(),	attribute->Value());
	}

	TiXmlNode	*node	=	0;
	for	(node	=	firstChild;	node;	node = node->NextSibling())
	{
		target->LinkEndChild(node->Clone());
	}
}


TiXmlNode	*TiXmlElement::Clone()const
{
	TiXmlElement *clone	=	new	TiXmlElement(Value());
	if (!clone)
	{
		return 0;
	}

	CopyTo(clone);
	return clone;
}


const	char *TiXmlElement::GetText()const
{
	const	TiXmlNode	*child = this->FirstChild();
	if (child)
	{
		const	TiXmlText	*childText = child->ToText();
		if (childText)
		{
			return childText->Value();
		}
	}
	return 0;
}


TiXmlDocument::TiXmlDocument():	TiXmlNode(TiXmlNode::DOCUMENT)
{
	tabsize	=	4;
	useMicrosoftBOM	=	false;
	ClearError();
}

TiXmlDocument::TiXmlDocument(const char	*documentName):	TiXmlNode(TiXmlNode::DOCUMENT)
{
	tabsize	=	4;
	useMicrosoftBOM	=	false;
	value	=	documentName;
	ClearError();
}


#ifdef TIXML_USE_STL
TiXmlDocument::TiXmlDocument(const std::string &documentName): TiXmlNode(TiXmlNode::DOCUMENT)
{
	tabsize	=	4;
	useMicrosoftBOM	=	false;
	value	=	documentName;
	ClearError();
}
#endif


TiXmlDocument::TiXmlDocument(const TiXmlDocument &copy): TiXmlNode(TiXmlNode::DOCUMENT)
{
	copy.CopyTo(this);
}


void TiXmlDocument::operator = (const	TiXmlDocument	&copy)
{
	Clear();
	copy.CopyTo(this);
}


bool TiXmlDocument::LoadFile(TiXmlEncoding encoding)
{
	// See STL_STRING_BUG	below.
	StringToBuffer buf(value);

	if (buf.buffer &&	LoadFile(buf.buffer, 0, 0, encoding))
	{
		return true;
	}

	return false;
}


bool TiXmlDocument::SaveFile()const
{
	// See STL_STRING_BUG	below.
	StringToBuffer buf(value);

	if (buf.buffer &&	SaveFile(buf.buffer))
	{
		return true;
	}

	return false;
}

bool TiXmlDocument::LoadFile(const char	*filename,void *mem,int len,TiXmlEncoding encoding)
{
	// There was a really	terrifying little	bug	here.	The	code:
	//		value	=	filename
	// in	the	STL	case,	cause	the	assignment method	of the std::string to
	// be	called.	What is	strange, is	that the std::string had the same
	// address as	it's c_str() method, and so	bad	things happen. Looks
	// like	a	bug	in the Microsoft STL implementation.
	// See STL_STRING_BUG	above.
	// Fixed with	the	StringToBuffer class.
	value	=	filename;

	// reading in	binary mode	so that	tinyxml	can	normalize	the	EOL
	NXU_FILE *file = nxu_fopen(value.c_str(),	"rb", mem, len);

	if (file)
	{
		bool result	=	LoadFile(file, encoding);
		nxu_fclose(file);
		return result;
	}
	else
	{
		SetError(TIXML_ERROR_OPENING_NXU_FILE, 0,	0, TIXML_ENCODING_UNKNOWN);
		return false;
	}
}

bool TiXmlDocument::LoadFile(NXU_FILE	*file, TiXmlEncoding encoding)
{
	if (!file)
	{
		SetError(TIXML_ERROR_OPENING_NXU_FILE, 0,	0, TIXML_ENCODING_UNKNOWN);
		return false;
	}

	// Delete	the	existing data:
	Clear();
	location.Clear();

	// Get the file	size,	so we	can	pre-allocate the string. HUGE	speed	impact.
	long length	=	0;
	nxu_fseek(file,	0, SEEK_END);
	length = (long) nxu_ftell(file);
	nxu_fseek(file,	0, SEEK_SET);

	// Strange case, but good	to handle	up front.
	if (length ==	0)
	{
		SetError(TIXML_ERROR_DOCUMENT_EMPTY, 0,	0, TIXML_ENCODING_UNKNOWN);
		return false;
	}

	// If	we have	a	file,	assume it	is all one big XML file, and read	it in.
	// The document	parser may decide	the	document ends	sooner than	the	entire file, however.	
	TIXML_STRING data;
	data.reserve(length);

	// Subtle	bug	here.	TinyXml	did	use	fgets. But from	the	XML	spec:
	// 2.11	End-of-Line	Handling
	// <snip>
	// <quote>
	// ...the	XML	processor	MUST behave	as if	it normalized	all	line breaks	in external
	// parsed	entities (including	the	document entity) on	input, before	parsing, by	translating
	// both	the	two-character	sequence #xD #xA and any #xD that	is not followed	by #xA to
	// a single	#xA	character.
	// </quote>
	//
	// It	is not clear fgets does	that,	and	certainly	isn't	clear	it works cross platform.
	// Generally,	you	expect fgets to	translate	from the convention	of the OS	to the c/unix
	// convention, and not work	generally.

	/*
	while( fgets(	buf, sizeof(buf),	file ) )
	{
	data +=	buf;
	}
	 */

	char *buf	=	new	char[length	+	1];
	buf[0] = 0;

	if (nxu_fread(buf, length, 1,	file)	!= 1)
	{
		SetError(TIXML_ERROR_OPENING_NXU_FILE, 0,	0, TIXML_ENCODING_UNKNOWN);
		return false;
	}

	const	char *lastPos	=	buf;
	const	char *p	=	buf;

	buf[length]	=	0;
	while	(*p)
	{
		assert(p < (buf	+	length));
		if (*p ==	0xa)
		{
			// Newline character.	No special rules for this. Append	all	the	characters
			// since the last	string,	and	include	the	newline.
			data.append(lastPos, (p	-	lastPos	+	1)); //	append,	include	the	newline
			++p; //	move past	the	newline
			lastPos	=	p; //	and	point	to the new buffer	(may be	0)
			assert(p <=	(buf + length));
		}
		else if	(*p	== 0xd)
		{
			// Carriage	return.	Append what	we have	so far,	then
			// handle	moving forward in	the	buffer.
			if ((p - lastPos)	>	0)
			{
				data.append(lastPos, p - lastPos); //	do not add the CR
			}
			data +=	(char)0xa; //	a	proper newline

			if (*(p	+	1) ==	0xa)
			{
				// Carriage	return - new line	sequence
				p	+= 2;
				lastPos	=	p;
				assert(p <=	(buf + length));
			}
			else
			{
				// it	was	followed by	something	else...that	is presumably	characters again.
				++p;
				lastPos	=	p;
				assert(p <=	(buf + length));
			}
		}
		else
		{
			++p;
		}
	}
	// Handle	any	left over	characters.
	if (p	-	lastPos)
	{
		data.append(lastPos, p - lastPos);
	}
	delete []	buf;
	buf	=	0;

	Parse(data.c_str(),	0, encoding);

	if (Error())
	{
		return false;
	}
	else
	{
		return true;
	}
}


bool TiXmlDocument::SaveFile(const char	*filename)const
{
	// The old c stuff lives on...
	NXU_FILE *fp = nxu_fopen(filename, "w");
	if (fp)
	{
		bool result	=	SaveFile(fp);
		nxu_fclose(fp);
		return result;
	}
	return false;
}


bool TiXmlDocument::SaveFile(NXU_FILE	*fp)const
{
	if (useMicrosoftBOM)
	{
		const	unsigned char	TIXML_UTF_LEAD_0 = 0xefU;
		const	unsigned char	TIXML_UTF_LEAD_1 = 0xbbU;
		const	unsigned char	TIXML_UTF_LEAD_2 = 0xbfU;

		nxu_fputc(TIXML_UTF_LEAD_0,	fp);
		nxu_fputc(TIXML_UTF_LEAD_1,	fp);
		nxu_fputc(TIXML_UTF_LEAD_2,	fp);
	}
	Print(fp,	0);
	return true;
}


void TiXmlDocument::CopyTo(TiXmlDocument *target)const
{
	TiXmlNode::CopyTo(target);

	target->error	=	error;
	target->errorDesc	=	errorDesc.c_str();

	TiXmlNode	*node	=	0;
	for	(node	=	firstChild;	node;	node = node->NextSibling())
	{
		target->LinkEndChild(node->Clone());
	}
}


TiXmlNode	*TiXmlDocument::Clone()const
{
	TiXmlDocument	*clone = new TiXmlDocument();
	if (!clone)
	{
		return 0;
	}

	CopyTo(clone);
	return clone;
}


void TiXmlDocument::Print(NXU_FILE *cfile, int depth)const
{
	const	TiXmlNode	*node;
	for	(node	=	FirstChild();	node;	node = node->NextSibling())
	{
		node->Print(cfile, depth);
		nxu_fprintf(cfile, "\n");
	}
}

void TiXmlDocument::StreamOut(TIXML_OSTREAM	*out)const
{
	const	TiXmlNode	*node;
	for	(node	=	FirstChild();	node;	node = node->NextSibling())
	{
		node->StreamOut(out);

		// Special rule	for	streams: stop	after	the	root element.
		// The stream	in code	will only	read one element,	so don't
		// write more	than one.
		if (node->ToElement())
		{
			break;
		}
	}
}


const	TiXmlAttribute *TiXmlAttribute::Next()const
{
	// We	are	using	knowledge	of the sentinel. The sentinel
	// have	a	value	or name.
	if (next->value.empty()	&& next->name.empty())
	{
		return 0;
	}
	return next;
}

TiXmlAttribute *TiXmlAttribute::Next()
{
	// We	are	using	knowledge	of the sentinel. The sentinel
	// have	a	value	or name.
	if (next->value.empty()	&& next->name.empty())
	{
		return 0;
	}
	return next;
}

const	TiXmlAttribute *TiXmlAttribute::Previous()const
{
	// We	are	using	knowledge	of the sentinel. The sentinel
	// have	a	value	or name.
	if (prev->value.empty()	&& prev->name.empty())
	{
		return 0;
	}
	return prev;
}

TiXmlAttribute *TiXmlAttribute::Previous()
{
	// We	are	using	knowledge	of the sentinel. The sentinel
	// have	a	value	or name.
	if (prev->value.empty()	&& prev->name.empty())
	{
		return 0;
	}
	return prev;
}

void TiXmlAttribute::Print(NXU_FILE	*cfile,	int	/*depth*/)const
{
	TIXML_STRING n,	v;

	PutString(name,	&n);
	PutString(value, &v);

	if (value.find('\"') ==	TIXML_STRING::npos)
	{
		nxu_fprintf(cfile, "%s=\"%s\"",	n.c_str(), v.c_str());
	}
	else
	{
		nxu_fprintf(cfile, "%s='%s'",	n.c_str(), v.c_str());
	}
}


void TiXmlAttribute::StreamOut(TIXML_OSTREAM *stream)const
{
	if (value.find('\"') !=	TIXML_STRING::npos)
	{
		PutString(name,	stream);
		(*stream)	<< "=" <<	"'";
		PutString(value, stream);
		(*stream)	<< "'";
	}
	else
	{
		PutString(name,	stream);
		(*stream)	<< "=" <<	"\"";
		PutString(value, stream);
		(*stream)	<< "\"";
	}
}

int	TiXmlAttribute::QueryIntValue(int	*ival)const
{
	if (sscanf(value.c_str(),	"%d",	ival)	== 1)
	{
		return TIXML_SUCCESS;
	}
	return TIXML_WRONG_TYPE;
}

int	TiXmlAttribute::QueryDoubleValue(double	*dval)const
{
	if (sscanf(value.c_str(),	"%lf", dval) ==	1)
	{
		return TIXML_SUCCESS;
	}
	return TIXML_WRONG_TYPE;
}

void TiXmlAttribute::SetIntValue(int _value)
{
	char buf[64];
	#if	defined(TIXML_SNPRINTF)
	TIXML_SNPRINTF(buf,	sizeof(buf), "%d", _value);
	#else
	sprintf(buf, "%d", _value);
	#endif
	SetValue(buf);
}

void TiXmlAttribute::SetDoubleValue(double _value)
{
	char buf[256];
	#if	defined(TIXML_SNPRINTF)
	TIXML_SNPRINTF(buf,	sizeof(buf), "%lf",	_value);
	#else
	sprintf(buf, "%lf",	_value);
	#endif
	SetValue(buf);
}

int	TiXmlAttribute::IntValue()const
{
	return atoi(value.c_str());
}

double TiXmlAttribute::DoubleValue()const
{
	return atof(value.c_str());
}


TiXmlComment::TiXmlComment(const TiXmlComment	&copy):	TiXmlNode(TiXmlNode::COMMENT)
{
	copy.CopyTo(this);
}


void TiXmlComment::operator	=	(const TiXmlComment	&base)
{
	Clear();
	base.CopyTo(this);
}


void TiXmlComment::Print(NXU_FILE	*cfile,	int	depth)const
{
	for	(int i = 0;	i	<	depth; i++)
	{
		nxu_fputs("		 ",	cfile);
	}
	nxu_fprintf(cfile, "<!--%s-->",	value.c_str());
}

void TiXmlComment::StreamOut(TIXML_OSTREAM *stream)const
{
	(*stream)	<< "<!--";
	//PutString( value,	stream );
	(*stream)	<< value;
	(*stream)	<< "-->";
}


void TiXmlComment::CopyTo(TiXmlComment *target)const
{
	TiXmlNode::CopyTo(target);
}


TiXmlNode	*TiXmlComment::Clone()const
{
	TiXmlComment *clone	=	new	TiXmlComment();

	if (!clone)
	{
		return 0;
	}

	CopyTo(clone);
	return clone;
}


void TiXmlText::Print(NXU_FILE *cfile, int depth)const
{
	if (cdata)
	{
		int	i;
		nxu_fprintf(cfile, "\n");
		for	(i = 0;	i	<	depth; i++)
		{
			nxu_fprintf(cfile, "		");
		}
		nxu_fprintf(cfile, "<![CDATA[");
		nxu_fprintf(cfile, "%s", value.c_str()); //	unformatted	output
		nxu_fprintf(cfile, "]]>\n");
	}
	else
	{
		TIXML_STRING buffer;
		PutString(value, &buffer);
		nxu_fprintf(cfile, "%s", buffer.c_str());
	}
}


void TiXmlText::StreamOut(TIXML_OSTREAM	*stream)const
{
	if (cdata)
	{
		(*stream)	<< "<![CDATA[" <<	value	<< "]]>";
	}
	else
	{
		PutString(value, stream);
	}
}


void TiXmlText::CopyTo(TiXmlText *target)const
{
	TiXmlNode::CopyTo(target);
	target->cdata	=	cdata;
}


TiXmlNode	*TiXmlText::Clone()const
{
	TiXmlText	*clone = 0;
	clone	=	new	TiXmlText("");

	if (!clone)
	{
		return 0;
	}

	CopyTo(clone);
	return clone;
}


TiXmlDeclaration::TiXmlDeclaration(const char	*_version, const char	*_encoding,	const	char *_standalone):	TiXmlNode(TiXmlNode::DECLARATION)
{
	version	=	_version;
	encoding = _encoding;
	standalone = _standalone;
}


#ifdef TIXML_USE_STL
TiXmlDeclaration::TiXmlDeclaration(const std::string &_version,	const	std::string	&_encoding,	const	std::string	&_standalone): TiXmlNode(TiXmlNode::DECLARATION)
{
	version	=	_version;
	encoding = _encoding;
	standalone = _standalone;
}
#endif


TiXmlDeclaration::TiXmlDeclaration(const TiXmlDeclaration	&copy):	TiXmlNode(TiXmlNode::DECLARATION)
{
	copy.CopyTo(this);
}


void TiXmlDeclaration::operator	=	(const TiXmlDeclaration	&copy)
{
	Clear();
	copy.CopyTo(this);
}


void TiXmlDeclaration::Print(NXU_FILE	*cfile,	int	/*depth*/)const
{
	nxu_fprintf(cfile, "<?xml	");

	if (!version.empty())
	{
		nxu_fprintf(cfile, "version=\"%s\" ",	version.c_str());
	}
	if (!encoding.empty())
	{
		nxu_fprintf(cfile, "encoding=\"%s\"	", encoding.c_str());
	}
	if (!standalone.empty())
	{
		nxu_fprintf(cfile, "standalone=\"%s\"	", standalone.c_str());
	}
	nxu_fprintf(cfile, "?>");
}

void TiXmlDeclaration::StreamOut(TIXML_OSTREAM *stream)const
{
	(*stream)	<< "<?xml	";

	if (!version.empty())
	{
		(*stream)	<< "version=\"";
		PutString(version, stream);
		(*stream)	<< "\" ";
	}
	if (!encoding.empty())
	{
		(*stream)	<< "encoding=\"";
		PutString(encoding,	stream);
		(*stream)	<< "\" ";
	}
	if (!standalone.empty())
	{
		(*stream)	<< "standalone=\"";
		PutString(standalone,	stream);
		(*stream)	<< "\" ";
	}
	(*stream)	<< "?>";
}


void TiXmlDeclaration::CopyTo(TiXmlDeclaration *target)const
{
	TiXmlNode::CopyTo(target);

	target->version	=	version;
	target->encoding = encoding;
	target->standalone = standalone;
}


TiXmlNode	*TiXmlDeclaration::Clone()const
{
	TiXmlDeclaration *clone	=	new	TiXmlDeclaration();

	if (!clone)
	{
		return 0;
	}

	CopyTo(clone);
	return clone;
}


void TiXmlUnknown::Print(NXU_FILE	*cfile,	int	depth)const
{
	for	(int i = 0;	i	<	depth; i++)
	{
		nxu_fprintf(cfile, "		");
	}
	nxu_fprintf(cfile, "<%s>", value.c_str());
}


void TiXmlUnknown::StreamOut(TIXML_OSTREAM *stream)const
{
	(*stream)	<< "<" <<	value	<< ">";	// Don't use entities	here!	It is	unknown.
}


void TiXmlUnknown::CopyTo(TiXmlUnknown *target)const
{
	TiXmlNode::CopyTo(target);
}


TiXmlNode	*TiXmlUnknown::Clone()const
{
	TiXmlUnknown *clone	=	new	TiXmlUnknown();

	if (!clone)
	{
		return 0;
	}

	CopyTo(clone);
	return clone;
}


TiXmlAttributeSet::TiXmlAttributeSet()
{
	sentinel.next	=	&sentinel;
	sentinel.prev	=	&sentinel;
}


TiXmlAttributeSet::~TiXmlAttributeSet()
{
	assert(sentinel.next ==	 &sentinel);
	assert(sentinel.prev ==	 &sentinel);
}


void TiXmlAttributeSet::Add(TiXmlAttribute *addMe)
{
	assert(!Find(TIXML_STRING(addMe->Name())));	// Shouldn't be	multiply adding	to the set.

	addMe->next	=	&sentinel;
	addMe->prev	=	sentinel.prev;

	sentinel.prev->next	=	addMe;
	sentinel.prev	=	addMe;
}

void TiXmlAttributeSet::Remove(TiXmlAttribute	*removeMe)
{
	TiXmlAttribute *node;

	for	(node	=	sentinel.next; node	!=	&sentinel; node	=	node->next)
	{
		if (node ==	removeMe)
		{
			node->prev->next = node->next;
			node->next->prev = node->prev;
			node->next = 0;
			node->prev = 0;
			return ;
		}
	}
	assert(0); //	we tried to	remove a non-linked	attribute.
}

const	TiXmlAttribute *TiXmlAttributeSet::Find(const	TIXML_STRING &name)const
{
	const	TiXmlAttribute *node;

	for	(node	=	sentinel.next; node	!=	&sentinel; node	=	node->next)
	{
		if (node->name ==	name)
		{
			return node;
		}
	}
	return 0;
}

TiXmlAttribute *TiXmlAttributeSet::Find(const	TIXML_STRING &name)
{
	TiXmlAttribute *node;

	for	(node	=	sentinel.next; node	!=	&sentinel; node	=	node->next)
	{
		if (node->name ==	name)
		{
			return node;
		}
	}
	return 0;
}

#ifdef TIXML_USE_STL
TIXML_ISTREAM	&operator	>> (TIXML_ISTREAM	&in, TiXmlNode &base)
{
	TIXML_STRING tag;
	tag.reserve(8	*1000);
	base.StreamIn(&in, &tag);

	base.Parse(tag.c_str(),	0, TIXML_DEFAULT_ENCODING);
	return in;
}
#endif


TIXML_OSTREAM	&operator	<< (TIXML_OSTREAM	&out,	const	TiXmlNode	&base)
{
	base.StreamOut(&out);
	return out;
}


#ifdef TIXML_USE_STL
std::string	&operator	<< (std::string	&out,	const	TiXmlNode	&base)
{
	std::ostringstream os_stream(std::ostringstream::out);
	base.StreamOut(&os_stream);

	out.append(os_stream.str());
	return out;
}
#endif


TiXmlHandle	TiXmlHandle::FirstChild()const
{
	if (node)
	{
		TiXmlNode	*child = node->FirstChild();
		if (child)
		{
			return TiXmlHandle(child);
		}
	}
	return TiXmlHandle(0);
}


TiXmlHandle	TiXmlHandle::FirstChild(const	char *value)const
{
	if (node)
	{
		TiXmlNode	*child = node->FirstChild(value);
		if (child)
		{
			return TiXmlHandle(child);
		}
	}
	return TiXmlHandle(0);
}


TiXmlHandle	TiXmlHandle::FirstChildElement()const
{
	if (node)
	{
		TiXmlElement *child	=	node->FirstChildElement();
		if (child)
		{
			return TiXmlHandle(child);
		}
	}
	return TiXmlHandle(0);
}


TiXmlHandle	TiXmlHandle::FirstChildElement(const char	*value)const
{
	if (node)
	{
		TiXmlElement *child	=	node->FirstChildElement(value);
		if (child)
		{
			return TiXmlHandle(child);
		}
	}
	return TiXmlHandle(0);
}


TiXmlHandle	TiXmlHandle::Child(int count)const
{
	if (node)
	{
		int	i;
		TiXmlNode	*child = node->FirstChild();
		for	(i = 0;	child	&& i < count;	child	=	child->NextSibling(),	++i)
		{
			// nothing
		}
		if (child)
		{
			return TiXmlHandle(child);
		}
	}
	return TiXmlHandle(0);
}


TiXmlHandle	TiXmlHandle::Child(const char	*value,	int	count)const
{
	if (node)
	{
		int	i;
		TiXmlNode	*child = node->FirstChild(value);
		for	(i = 0;	child	&& i < count;	child	=	child->NextSibling(value), ++i)
		{
			// nothing
		}
		if (child)
		{
			return TiXmlHandle(child);
		}
	}
	return TiXmlHandle(0);
}


TiXmlHandle	TiXmlHandle::ChildElement(int	count)const
{
	if (node)
	{
		int	i;
		TiXmlElement *child	=	node->FirstChildElement();
		for	(i = 0;	child	&& i < count;	child	=	child->NextSiblingElement(), ++i)
		{
			// nothing
		}
		if (child)
		{
			return TiXmlHandle(child);
		}
	}
	return TiXmlHandle(0);
}


TiXmlHandle	TiXmlHandle::ChildElement(const	char *value, int count)const
{
	if (node)
	{
		int	i;
		TiXmlElement *child	=	node->FirstChildElement(value);
		for	(i = 0;	child	&& i < count;	child	=	child->NextSiblingElement(value),	++i)
		{
			// nothing
		}
		if (child)
		{
			return TiXmlHandle(child);
		}
	}
	return TiXmlHandle(0);
}

};
